package net.lzzy.practices.services;

import net.lzzy.practices.entities.Applicant;
import net.lzzy.practices.entities.Course;
import net.lzzy.practices.entities.User;
import net.lzzy.practices.repositories.ApplicantRepository;
import net.lzzy.practices.repositories.CourseRepository;
import net.lzzy.practices.repositories.UserRepository;
import net.lzzy.practices.utils.AuthUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.UUID;

/**
 * @author  Jaymo on 2022/5/25
 */
@Service
public class ApplicantServiceImpl implements ApplicantService{
    private  final  ApplicantRepository repository;
    private  final  UserRepository uRepository;
    private  final  CourseRepository cRepository;

    @Autowired
    public  ApplicantServiceImpl(ApplicantRepository repository, CourseRepository cRepository, UserRepository uRepository)  {
        this.repository = repository;
        this.uRepository = uRepository;
        this.cRepository = cRepository;
    }

    @Override
    public  Applicant apply(UUID studentId,UUID courseId,String token){
        if (AuthUtils.invalid(studentId,token)){
            return null;
        }
        User student = uRepository.findById(studentId).orElse(null);
        Course course = cRepository.findById(courseId).orElse(null);
        if (student ==null || course ==null){
            return  null;
        }
        Applicant applicant = new Applicant();
        applicant.setCourse(course);
        applicant.setStudent(student);
        applicant.setStatus(Applicant.TYPE_APPLYING);
        return  repository.save(applicant);
    }

    @Override
    public List<Applicant> getEnrolledApplicants(UUID studentId){
        return  repository.findApplicantsByStudentIdEqualsAndStatusEqualsOrderByApplyTimeDesc(studentId,Applicant.TYPE_APPROVED);
    }

    @Override
    public  List<Applicant> getApplyingApplicants(UUID studentId){
        return  repository.findApplicantsByStudentIdEqualsAndStatusEqualsOrderByApplyTimeDesc(studentId,Applicant.TYPE_APPLYING);
    }

    @Override
    public  List<Applicant> getDeclinedApplicants(UUID studentId){
        return  repository.findApplicantsByStudentIdEqualsAndStatusEqualsOrderByApplyTimeDesc(studentId,Applicant.TYPE_DECLINED);
    }

    private  Applicant update(UUID applicantId,String token,int status){
        Applicant applicant = repository.findById(applicantId).orElse(null);
        if (applicant == null){
            return  null;
        }
        Course course = applicant.getCourse();
        UUID teacherId =course.getTeacher().getId();
        if (AuthUtils.invalid(teacherId,token)){
            return  null;
        }
        applicant.setStatus(status);
        return  repository.save(applicant);
    }

  @Transactional(rollbackFor = Exception.class)
  @Override
    public  Applicant approve(UUID applicantId,String token){
        Applicant applicant = update(applicantId,token,Applicant.TYPE_APPROVED);
        if (applicant != null){
            Course course = applicant.getCourse();
            User student = applicant.getStudent();
            List<User> students = course.getStudents();
            if (!students.contains(student)){
                students.add(student);
            }
            course.setStudents(students);
            applicant.setCourse(cRepository.save(course));
        }
        return  applicant;
    }

    @Transactional(rollbackFor =  Exception.class)
    @Override
    public Applicant decline(UUID applicantId, String token){
        return  update(applicantId,token,Applicant.TYPE_DECLINED);
    }

    @Override
    public List<Applicant> getEnrolledStudents(UUID courseId){
        return  repository.findApplicantsByCourseIdEqualsAndStatusEqualsOrderByApplyTimeDesc(courseId,Applicant.TYPE_APPROVED);
    }

    @Override
    public  List<Applicant> getApplyingStudents(UUID courseId){
        return  repository.findApplicantsByCourseIdEqualsAndStatusEqualsOrderByApplyTimeDesc(courseId,Applicant.TYPE_APPLYING);
    }

    @Override
    public  List<Applicant> getDeclinedStudents(UUID courseId){
        return  repository.findApplicantsByCourseIdEqualsAndStatusEqualsOrderByApplyTimeDesc(courseId,Applicant.TYPE_DECLINED);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public  Course removeStudent(UUID courseId, UUID studentId, String token){
        Course course = cRepository.findById(courseId).orElse(null);
        if (course == null){
            return null;
        }
        UUID teacherId = course.getTeacher().getId();
        if (AuthUtils.invalid(teacherId,token)) {
            return  null;
        }
        course.getStudents().removeIf(s -> s.getId().equals(studentId));
        Applicant applicant = repository.findApplicantByCourseIdAndStudentId(courseId,studentId);
        if (applicant != null){
            update(applicant.getId(),token,Applicant.TYPE_DECLINED);
        }
        return  cRepository.save(course);
    }
}
